package com.letoken.platform.pub.util;

import org.bitcoinj.core.Base58;
import org.bouncycastle.util.encoders.Hex;
import org.web3j.crypto.*;
import org.web3j.utils.Numeric;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @version 1.0
 * @author： Christopher
 * @date： 2022/1/20 16:52
 */
public class SignUtil {


    /**
     * eth 对普通信息进行签名
     *
     * @param message    签名内容
     * @param privateKey 私钥
     * @return
     */
    public static Map<String, String> signature(String message, String privateKey) {
        byte[] data = Sign.getEthereumMessageHash(message.getBytes());
        // Generate ECKeyPair from the private key
        ECKeyPair ecKeyPair = Credentials.create(privateKey).getEcKeyPair();
        // Sign the wallet address and private key
        Sign.SignatureData signatureData = Sign.signMessage(data, ecKeyPair, false);
        // Hex to String
        String signature_R = Numeric.toHexString(signatureData.getR());
        String signature_S = Numeric.toHexString(signatureData.getS());
        String signature_V = Numeric.toHexString(signatureData.getV());
        String signature = signature_R + signature_S.substring(2) + signature_V.substring(2);
        Map<String, String> hashMap = new HashMap<>(3);
        hashMap.put("r", signature_R);
        hashMap.put("s", signature_S);
        hashMap.put("v", signature_V);
        hashMap.put("signature", signature);
        return hashMap;
    }

    /**
     * eth 解签
     *
     * @param message   签名信息
     * @param signature 密文
     * @return
     */
    public static boolean recoverSignature(String message, String signature, String publicKey) {
        boolean match = false;
        try {
            byte[] messageHash = Sign.getEthereumMessageHash(message.getBytes());
            byte[] signatureBytes = Numeric.hexStringToByteArray(signature);
            byte v = signatureBytes[64];
            if (v < 27) {
                v += 27;
            }
            Sign.SignatureData sd = new Sign.SignatureData(v
                    , (byte[]) Arrays.copyOfRange(signatureBytes, 0, 32)
                    , (byte[]) Arrays.copyOfRange(signatureBytes, 32, 64));
            String addressRecovered = null;
            // Iterate for each possible key to recover
            for (int i = 0; i < 4; i++) {
                BigInteger address = Sign.recoverFromSignature(
                        (byte) i,
                        new ECDSASignature(new BigInteger(1, sd.getR()), new BigInteger(1, sd.getS())),
                        messageHash);
                if (address != null) {
                    addressRecovered = "0x" + Keys.getAddress(address);
                    if (addressRecovered.equalsIgnoreCase(publicKey)) {
                        match = true;
                        break;
                    }
                }
            }
        } catch (Exception e) {
            return match;
        }
        return match;
    }
}
